package com.autonavi.yunda.yunji.core.service;

import com.autonavi.yunda.yunji.common.exception.AmapPreconditions;
import com.autonavi.yunda.yunji.core.enums.FunctionStatus;
import com.autonavi.yunda.yunji.core.model.dto.FunctionConfigDTO;
import com.autonavi.yunda.yunji.core.model.dto.FunctionProjectMappingDTO;
import com.autonavi.yunda.yunji.core.model.dto.ProjectDTO;
import com.autonavi.yunda.yunji.core.model.mappers.FunctionProjectMappingMapper;
import com.autonavi.yunda.yunji.core.model.mappers.ProjectMapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.springframework.stereotype.Repository;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.sql.Timestamp;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author sunzhenbang
 */
@Repository
public class FunctionProjectMappingService {
    @Resource
    ProjectMapper projectMapper;
    @Resource
    private FunctionProjectMappingMapper functionProjectMappingMapper;

    public Integer insertBatchSomeColumn(List<FunctionProjectMappingDTO> dtos) {
        return functionProjectMappingMapper.insertBatchSomeColumn(dtos);
    }

    public List<Long> listFunctionIdsByProjectId(String projectId) {
        return functionProjectMappingMapper.listDatasourceIdsByPid(projectId);
    }

    public Map<Long, Set<String>> fetchFunctionProjectIdMap(List<String> projectIds) {
        if (CollectionUtils.isEmpty(projectIds)) {
            return new HashMap<>();
        }
        return functionProjectMappingMapper.listByProjectIds(projectIds)
                .stream().collect(Collectors.groupingBy(FunctionProjectMappingDTO::getFunctionId,
                        Collectors.mapping(FunctionProjectMappingDTO::getProjectId, Collectors.toSet())));
    }

    public List<FunctionProjectMappingDTO> listByFunctionId(Long functionId) {
        return functionProjectMappingMapper.listFunctionByFId(functionId);
    }

    public void deleteBatchIds(List<Long> ids) {
        functionProjectMappingMapper.deleteBatchIds(ids);
    }

    /**
     * 维护yunji_function_project_mapping表
     *  1. 去除表中functionId和传参想等,但是项目id不是给定的集合中的数据
     *  2. 忽略原来表中已存在的关系,插入新映射关系
     * @param functionId
     * @param syncProjectIds
     * @param operator
     */
    public void updateMapping(Long functionId, List<String> syncProjectIds, String operator) {
        // 1. 查询yunji_project表，获取实际在表中存在的project_id集合
        List<String> updateProjectIds = projectMapper.selectList(new QueryWrapper<ProjectDTO>().in("project_id", syncProjectIds))
                .stream().map(ProjectDTO::getProjectId).collect(Collectors.toList());
        AmapPreconditions.checkArgumentForUser(!CollectionUtils.isEmpty(updateProjectIds), "函数关联的项目不存在");
        // 2. 查询yunji_function_project_mapping获取所有与functionId有关的映射
        List<FunctionProjectMappingDTO> functionProjectList = listByFunctionId(functionId);
        // 3. 找出步骤2的结果中，不包含updateProjectIds集合中的yunji_function_project_mapping记录
        List<Long> deleteBatchIds = functionProjectList.stream().filter(f -> !updateProjectIds.contains(f.getProjectId()))
                .map(FunctionProjectMappingDTO::getId).collect(Collectors.toList());
        // 直接删除
        if (!CollectionUtils.isEmpty(deleteBatchIds)) {
            deleteBatchIds(deleteBatchIds);
        }
        // 4. 如果yunji_function_project_mapping中已经存在指定的projectId和functionId的记录，将其从addProjectIds剔除
        List<String> addProjectIds = new ArrayList<>(updateProjectIds);
        functionProjectList.forEach(dp -> addProjectIds.removeIf(pid -> pid.equals(dp.getProjectId())));
        // 最终获取需要插入到yunji_function_project_mapping中
        if (!CollectionUtils.isEmpty(addProjectIds)) {
            insertBatchSomeColumn(toFunctionProjectMappingDTOList(functionId, addProjectIds, operator));
        }
    }

    public List<FunctionProjectMappingDTO> toFunctionProjectMappingDTOList(Long functionId, List<String> projectIds, String operator) {
        ArrayList<FunctionProjectMappingDTO> functionProjectList = new ArrayList<>();
        projectIds.forEach(productId -> functionProjectList.add(
                FunctionProjectMappingDTO.builder()
                        .functionId(functionId)
                        .projectId(productId)
                        .createUser(operator)
                        .updateUser(operator)
                        .createTime(new Timestamp(System.currentTimeMillis()))
                        .updateTime(new Timestamp(System.currentTimeMillis()))
                        .build())
        );
        return functionProjectList;
    }

    /**
     * 本地化/离线方案-获取导出项目的可用函数列表
     * @param projectId    项目ID
     * @return  函数列表
     */
    public List<FunctionConfigDTO> listFunctionByProjectId(String projectId) {
        return functionProjectMappingMapper.listFunctionByProjectId(projectId, FunctionStatus.PUBLISHED.name());
    }
}
